home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / tools / profiler / cprof / cprof.c
Encoding:
C/C++ Source or Header  |  1989-10-04  |  12.7 KB  |  515 lines

  1. /*
  2.  * A C program profiler.
  3.  *
  4.  * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that the above copyright notice and this paragraph are
  8.  * duplicated in all such forms and that any documentation,
  9.  * advertising materials, and other materials related to such
  10.  * distribution and use acknowledge that the software was developed
  11.  * by Diomidis Spinellis.
  12.  *
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  *
  17.  *
  18.  * Author: Diomidis D. Spinellis (dds@cc.ic.ac.uk)
  19.  *       Myrsinis 1
  20.  *       GR-145 62 Kifisia
  21.  *       GREECE
  22.  *
  23.  *    Peter J. Holzer (hjphr@ehoney.tuwien.ac.at)
  24.  *    Erlachgasse 70
  25.  *    A-1100 Wien
  26.  *    AUSTRIA
  27.  *
  28.  * Modification history:
  29.  *
  30.  * $Log:    PROF.C^v $
  31.  * Revision 1.1  88/11/20  17:33:16  dds
  32.  * Initial revision
  33.  *
  34.  * Revision 1.2        89-09-03    hjp
  35.  * Support for Turbo C added
  36.  *
  37.  */
  38.  
  39. #include <stddef.h>
  40. #include <stdlib.h>
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include <dos.h>
  44.  
  45. #ifdef __TURBOC__
  46. #define _dos_getvect(x) getvect(x)
  47. #define _dos_setvect(i,f) setvect(i,f)
  48. #define onexit(x)    atexit(x)
  49. #define ENDCODE_SYMB    "DATA"
  50. #else
  51. #define ENDCODE_SYMB    "ENDCODE"
  52. #endif
  53.  
  54. /* Linker output maximum line length */
  55. #define LINELEN 129
  56. /* Linker output maximum symbol length */
  57. #define STRLEN    65
  58.  
  59. /* Entries can be absolute or relocatable */
  60. enum relocation { absolute, relocatable };
  61.  
  62. /* Function prototypes */
  63. static void add_proc(char * name, unsigned long addr, enum relocation rel);
  64. static void adjust_proc(long main_offset);
  65. static void install_int(void);
  66. #ifdef __TURBOC__
  67. static void prof_end(void);
  68. #else
  69. static int prof_end(void);
  70. #endif
  71. static void * xmalloc(size_t size);
  72. static void * xrealloc(void * buffer, size_t size);
  73. static char * strsave(char * string);
  74. #ifdef __TURBOC__
  75. static void interrupt far timer_handler (
  76.     unsigned bp,unsigned di,unsigned si,unsigned ds,unsigned es,
  77.     unsigned dx,unsigned cx,unsigned bx,unsigned ax,
  78.     unsigned ip,unsigned cs,unsigned flags);
  79. #else
  80. static void interrupt far timer_handler (unsigned es,unsigned ds,unsigned di,unsigned si,unsigned bp,
  81.         unsigned sp,unsigned bx,unsigned dx,unsigned cx,unsigned ax,unsigned ip,unsigned cs,unsigned flags);
  82. #endif
  83. void main(int argc, char *argv[]);
  84. #ifdef DEBUG
  85. static void dump_table(void);
  86. static void test_search(void);
  87. static void disp(long n);
  88. #endif
  89.  
  90. static char rcsid[] = "$Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $";
  91. static char VER[] = "@(#)    prof.c    1.2    89-09-03    hjp";
  92.  
  93. void
  94. prof_start(char * argv0)
  95. {
  96.     FILE *f;
  97.     static char fname[65];
  98.     static char line[LINELEN];
  99.     static char str1[STRLEN], str2[STRLEN], str3[STRLEN], str4[STRLEN],
  100.             str5[STRLEN];
  101.     enum {searchsegs, scansegs, searchprocs, scanprocs } state;
  102.     static char *state_errs[] = {
  103.         "start of segment definitions",
  104.         ENDCODE_SYMB " segment definition",
  105.         "the ``Publics by Value'' line",
  106.         "address greater than " ENDCODE_SYMB " was found"
  107.     };
  108.     unsigned int seg, off;
  109.     unsigned long endcode;
  110.     int linenum = 0;
  111.     unsigned long main_addr, addr;
  112.     long main_offset = -1;
  113.     void far * main_p;
  114.  
  115.     /* Find the address of main to adjust everything else */
  116.     main_p = (void far *)main;
  117.     main_addr = ((unsigned long)FP_SEG(main_p) << 4) +
  118.              (unsigned long)FP_OFF(main_p);
  119.     #ifdef DEBUG
  120.     printf("main=%08lx\n", main_addr);
  121.     #endif
  122.  
  123.     add_proc("DOS", 0l, absolute);
  124.     strcpy(fname, argv0);
  125.     strcpy(strrchr(fname, '.'), ".MAP");
  126.  
  127.     if ((f = fopen(fname, "r")) == NULL) {
  128.         perror(fname);
  129.         exit(1);
  130.     }
  131.  
  132.     state = searchsegs;
  133.     while (fgets(line, LINELEN, f)) {
  134.         linenum++;
  135.         if (* line == '\n') continue;    /*    ignore empty lines    */
  136.         switch (state) {
  137.         case searchsegs :
  138.             if (sscanf(line, " %s %s %s %s %s ",
  139.                    str1, str2, str3, str4, str5) == 5 &&
  140.                    strcmp(str1, "Start") == 0 &&
  141.                    strcmp(str2, "Stop") == 0 &&
  142.                    strcmp(str3, "Length") == 0 &&
  143.                    strcmp(str4, "Name") == 0 &&
  144.                    strcmp(str5, "Class") == 0)
  145.                 state = scansegs;
  146.             break;
  147.         case scansegs :
  148.             if (sscanf(line, " %lxH %*lxH %*lxH %*s %s ",
  149.                    &endcode, str1) != 2) {
  150.                 fprintf(stderr,
  151.                     "%s(%d) : Unable to parse line : %s\n",
  152.                     fname, linenum, line);
  153.                 exit(1);
  154.             }
  155.             if (strcmp(str1, ENDCODE_SYMB) == 0)
  156.                 state = searchprocs;
  157.             break;
  158.         case searchprocs :
  159.             if (sscanf(line, " %s %s %s %s ", str1, str2, str3,
  160.                    str4) == 4 &&
  161.                    strcmp(str1, "Address") == 0 &&
  162.                    strcmp(str2, "Publics") == 0 &&
  163.                    strcmp(str3, "by") == 0 &&
  164.                    strcmp(str4, "Value") == 0)
  165.                 state = scanprocs;
  166.             break;
  167.         case scanprocs :
  168.             if (*line == '\n' || sscanf(line, " %x:%x Abs %s ",
  169.                             &seg, &off, str1) == 3)
  170.                 break;
  171.             if (sscanf(line, " %x:%x %s ", &seg, &off, str1) != 3) {
  172.                 fprintf(stderr,
  173.                     "%s(%d) : Unable to parse line : %s\n",
  174.                     fname, linenum, line);
  175.                 exit(1);
  176.             }
  177.             addr = ((unsigned long)seg << 4) + (unsigned long)off;
  178.             if (strcmp(str1, "_main") == 0)
  179.                 main_offset = addr;
  180.             add_proc(str1, addr + main_addr, relocatable);
  181.             if (addr > endcode) {
  182.                 /*
  183.                  * Add here in ascending order any important
  184.                  * memory bounds. One idea would be to partition
  185.                  * the BIOS in tasks e.g. printer, screen etc.
  186.                  */
  187.                 add_proc("UNKOWN", addr + main_addr + 1,
  188.                       relocatable);
  189.                 add_proc("EGA_BIOS", 0xc0000l, absolute);
  190.                 add_proc("FDISK_BIOS", 0xc8000l, absolute);
  191.                 add_proc("SYSTEM_ROM", 0xf0000l, absolute);
  192.                 add_proc("SYSTEM_BIOS", 0xfe000l, absolute);
  193.                 add_proc("OUTER_SPACE", (unsigned long)-1l,
  194.                       absolute);
  195.                 fclose(f);
  196.                 if (main_offset == -1) {
  197.                     fputs("_main address not found\n",
  198.                           stderr);
  199.                     exit(1);
  200.                 }
  201.                 adjust_proc(main_offset);
  202.                 #ifdef __TURBOC__
  203.                 if (atexit(prof_end) != 0) {
  204.                     fputs("atexit failed\n", stderr);
  205.                     exit(1);
  206.                 }
  207.                 #else
  208.                 if (onexit(prof_end) == NULL) {
  209.                     fputs("onexit failed\n", stderr);
  210.                     exit(1);
  211.                 }
  212.                 #endif
  213.                 #ifdef DEBUG
  214.                 dump_table();
  215.                 test_search();
  216.                 #endif
  217.                 install_int();
  218.                 return ;
  219.             }
  220.         }
  221.     }
  222.     /* Something went wrong */
  223.     fprintf(stderr, "%s(%d) EOF reached before %s\n", fname, linenum,
  224.         state_errs[state]);
  225.     exit(1);
  226. }
  227.  
  228. /* The structure where procedures are kept */
  229. static struct proc_data {
  230.     unsigned long addr ;            /* Procedure start address */
  231.     unsigned long count ;            /* Hit count set by interrupt */
  232.     char *name ;                /* Procedure name */
  233.     enum relocation rel ;            /* Relocation type */
  234. } *procs;
  235.  
  236. /* Number of procedures and allocated memory */
  237. static int procnum, procalloc;
  238.  
  239. /* Size of memory allocation chunk */
  240. #define BLK    30
  241.  
  242. /* Define a procedure */
  243. static void
  244. add_proc(char * name, unsigned long addr, enum relocation rel)
  245. {
  246.     if (procs == NULL) {
  247.         procs = xmalloc(sizeof(struct proc_data) * BLK);
  248.         procalloc = BLK;
  249.     }
  250.     procs[procnum].addr = addr;
  251.     procs[procnum].count = 0l;
  252.     procs[procnum].name = strsave(name);
  253.     procs[procnum].rel = rel;
  254.     procnum++;
  255.     if (procnum >= procalloc) {
  256.         procalloc += BLK;
  257.         procs = xrealloc(procs, sizeof(struct proc_data) *
  258.                   procalloc);
  259.     }
  260. }
  261.  
  262. /*
  263.  * Adjust downwards the memory allocated for procedure data storage
  264.  * and subtract main_offset.
  265.  */
  266. static void
  267. adjust_proc(long main_offset)
  268. {
  269.     struct proc_data *pp;
  270.  
  271.     procs = xrealloc(procs, sizeof(struct proc_data) * procnum);
  272.     for (pp = procs ; pp < &procs[procnum] ; pp++)
  273.         if (pp->rel == relocatable)
  274.             pp->addr -= main_offset;
  275. }
  276.  
  277. /* Timer interrupt (Do not use 0x1c since it is always called from BIOS) */
  278. #define TIMER_INT    8
  279.  
  280. /* Old timer handler to chain to */
  281. static void (interrupt far * old_timer_handler)(void);
  282.  
  283. /* Disable timer handler and print the profiling results */
  284.  
  285. #ifdef __TURBOC__
  286. static void
  287. #else
  288. static int
  289. #endif
  290. prof_end(void)
  291. {
  292.     register i;
  293.     FILE *f;
  294.  
  295.     _dos_setvect(TIMER_INT, old_timer_handler);
  296.     if ((f = fopen("prof.out", "w")) == NULL) {
  297.         perror("prof.out");
  298.         #ifdef __TURBOC__
  299.         return;
  300.         #else
  301.         return 1;
  302.         #endif
  303.     }
  304.     for (i = 0 ; i < procnum ; i++)
  305.         fprintf(f, "%s %ld\n", procs[i].name, procs[i].count);
  306.     fclose(f);
  307.     #ifdef __TURBOC__
  308.     return;
  309.     #else
  310.     return 0;
  311.     #endif
  312. }
  313.  
  314. /* Allocate memory with error checking. */
  315. static void *
  316. xmalloc(size_t size)
  317. {
  318.     void * p;
  319.  
  320.     if ((p = malloc(size)) == NULL) {
  321.         fputs("Profiler : Out of memory\n", stderr);
  322.         exit(1);
  323.     }
  324.     return p;
  325. }
  326.  
  327. /* Reallocate memory with error checking.  */
  328. static void *
  329. xrealloc(void * buffer, size_t size)
  330. {
  331.     void * p;
  332.  
  333.  
  334.     if ((p = realloc(buffer, size)) == NULL) {
  335.         fputs("Profiler : Out of memory\n", stderr);
  336.         exit(1);
  337.     }
  338.     return p;
  339. }
  340.  
  341. /* Save a string in allocated memory */
  342. static char *
  343. strsave(char * string)
  344. {
  345.     return strcpy(xmalloc(strlen(string) + 1), string);
  346. }
  347.  
  348. /* The timer interrupt handler */
  349. #ifdef __TURBOC__
  350. static void interrupt far
  351. timer_handler(unsigned bp,unsigned di,unsigned si,unsigned ds,unsigned es,
  352.           unsigned dx,unsigned cx,unsigned bx,unsigned ax,
  353.           unsigned ip,unsigned cs,unsigned flags)
  354. #else
  355. static void interrupt far
  356. timer_handler(unsigned es,unsigned ds,unsigned di,unsigned si,unsigned bp,
  357.           unsigned sp,unsigned bx,unsigned dx,unsigned cx,unsigned ax,
  358.           unsigned ip,unsigned cs,unsigned flags)
  359. #endif
  360. {
  361.     long addr;
  362.     int lower, upper, middle;
  363.  
  364.     addr = ((unsigned long)cs << 4) + (unsigned long)ip;
  365.  
  366.     #ifdef DEBUG
  367.     disp(addr);
  368.     #endif
  369.     /*
  370.      * Precondition :
  371.      * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
  372.      */
  373.     lower = 0;
  374.     upper = procnum - 2;
  375.     /*
  376.      * Invariant :
  377.      * { a[l] <= addr < a[u] }
  378.      * Variant :
  379.      * { u - l }
  380.      */
  381.     while (upper - lower > 1) {
  382.         middle = (lower + upper) / 2;
  383.         /*
  384.          * m = l + (u - l) / 2 = (u + l) / 2
  385.          * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
  386.          * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
  387.          * m = l + (u - l) / 2 >= l + 1 implies m > l
  388.          */
  389.         if (procs[middle].addr <= addr)
  390.             lower = middle;
  391.         else
  392.             upper = middle;
  393.     }
  394.     /*
  395.      * Postcondition :
  396.      * { a[f] <= addr < a[f + 1] } which can be expressed as:
  397.      * { a[l] <= addr < a[u] & u = l + 1 }
  398.      */
  399.     procs[lower].count++;
  400.     (*old_timer_handler)();
  401. #ifndef __TURBOC__
  402.     /* Silence warnings */
  403.     (void)(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags);
  404. #endif
  405. }
  406.  
  407. /* Install the interrupt driver */
  408. static void
  409. install_int(void)
  410. {
  411.     old_timer_handler = _dos_getvect(TIMER_INT);
  412.     _dos_setvect(TIMER_INT, timer_handler);
  413. }
  414.  
  415. #ifdef DEBUG
  416.  
  417. /* Very fast display of a number on the screen. (Define MDA for mono adapter) */
  418.  
  419. #ifdef MDA
  420. #define REGEN_BASE 0xb0000000
  421. #else /* CGA */
  422. #define REGEN_BASE 0xb8000000
  423. #endif
  424.  
  425. static void
  426. disp(long n)
  427. {
  428.     register i;
  429.     char far * sb = (char far *)(REGEN_BASE + 20);
  430.  
  431.     for (i = 0 ; i < 8 ; i++) {
  432.         *sb = "0123456789abcdef"[(int)n & 0xF];
  433.         n >>= 4;
  434.         sb -= 2;
  435.     }
  436. }
  437.  
  438. /* Test the binary search algorithm */
  439. static void
  440. pr_name(long addr)
  441. {
  442.     int lower, upper, middle;
  443.  
  444.     /*
  445.      * Precondition :
  446.      * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
  447.      */
  448.     lower = 0;
  449.     upper = procnum - 2;
  450.     /*
  451.      * Invariant :
  452.      * { a[l] <= addr < a[u] }
  453.      * Variant :
  454.      * { u - l }
  455.      */
  456.     while (upper - lower > 1) {
  457.         middle = (lower + upper) / 2;
  458.         /*
  459.          * m = l + (u - l) / 2 = (u + l) / 2
  460.          * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
  461.          * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
  462.          * m = l + (u - l) / 2 >= l + 1 implies m > l
  463.          */
  464.         if (procs[middle].addr <= addr)
  465.             lower = middle;
  466.         else
  467.             upper = middle;
  468.         printf("%5d %5d %5d\n", lower, middle, upper);
  469.     }
  470.     /*
  471.      * Postcondition :
  472.      * { a[f] <= addr < a[f + 1] } which can be expressed as:
  473.      * { a[l] <= addr < a[u] & u = l + 1 }
  474.      */
  475.     puts(procs[lower].name);
  476. }
  477.  
  478. /* Interact with the user testing the search algorithm */
  479. static void
  480. test_search()
  481. {
  482.     char buff[80];
  483.     long addr;
  484.  
  485.     puts("Enter -1 to finish");
  486.     do{
  487.         gets(buff);
  488.         sscanf(buff, " %lx ", &addr);
  489.         pr_name(addr);
  490.     } while (addr != -1l);
  491. }
  492.  
  493. /* Dump the procedure table */
  494. static void
  495. dump_table()
  496. {
  497.     struct proc_data *pd;
  498.  
  499.     for (pd = procs ; pd < &procs[procnum] ; pd++)
  500.         printf("%08lx    %s\n", pd->addr, pd->name);
  501. }
  502. #endif
  503. ----------------------------------------------------------------
  504.  _______________________________________________________________
  505. |    __   |                            |
  506. |  |   |  \  | Peter J. Holzer                    |
  507. |  |___|__/  | Technische Universitaet Wien            |
  508. |  |   |     |                            |
  509. |  |   |     | ...!uunet!mcvax!tuvie!asupa!honey!hjphr        |
  510. |  ____/     |--------------------------------------------------|
  511. |         | Think of it as evolution in action -- Tony Rand    |
  512. |____________|__________________________________________________|
  513.  
  514.  
  515.